/*
 * This file is part of Xer.
 *
 * Simple interpreter for the X language
 * Copyright (C)  Michael Morckos 2009 <mikey.morckos@gmail.com>
 *
 * Xer is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Xer is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with Xer.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "X_keywords.h"
#include "X_lexer.h"

void init() {
	symbol_table = malloc(sizeof(Token) * 30000);
	currC = '\0'; 
	tmp = '\0';
	pointer = 0;
	linecount = 0;
	tokencount = 0;
	num = 0;
	errflag = 0;
	lexerflag = 1;
	lexerdone = 0;
}	

void flushlexem() {
	short i;
	for(i = 0; i < 1024; i++) {
		currlexem[i] = '\0';
	}	
	pointer = 0;
	num = 0;
	lexerflag = 1;	
}

void update_symbol_table() {
	Token tk;
	strcpy(tk.lexem, currlexem);
	tk.num_val = num;
	if(!strcmp(currlexem, _LET) || !strcmp(currlexem, _LETREC) || !strcmp(currlexem, _FUNC) ||
		!strcmp(currlexem, _IF) || !strcmp(currlexem, _ELSE) || !strcmp(currlexem, _IN)) {
		strcpy(tk.type, _KEYWORD);
	}
	else if(!strcmp(currlexem, _NOT) || !strcmp(currlexem, _GETSTR) || 
			!strcmp(currlexem, _GETINT) || !strcmp(currlexem, _PRINT)) {
			strcpy(tk.type, _FUNCTION);
	}		
	else if(currlexem[0] == '"') {
		strcpy(tk.type, _STRLITERAL);
	}
	else if(isdigit(currlexem[0])) {
		strcpy(tk.type, _NUMLITERAL);
	}
	else if(!strcmp(currlexem, "&&")) {
		strcpy(tk.type, _CA);
	}
	else if(!strcmp(currlexem, "||")) {
		strcpy(tk.type, _CO);
	}
	else if(currlexem[0] == '=') {
		if(strlen(currlexem) == 1) {
			strcpy(tk.type, _AO);
		}
		else {
			strcpy(tk.type, _EQ);
		}		
	}
	else {
		switch(currlexem[0]) {
			case '+' : strcpy(tk.type, _PO); break;
			case '-' : strcpy(tk.type, _MO); break;
			case '*' : strcpy(tk.type, _MB); break;
			case '/' : strcpy(tk.type, _DB); break;
			case ',' : strcpy(tk.type, _FA); break;
			case ';' : strcpy(tk.type, _SM); break;
			case '>' : strcpy(tk.type, _GT); break;
			case '<' : strcpy(tk.type, _LT); break;
			case '{' : strcpy(tk.type, _LC); break;
			case '}' : strcpy(tk.type, _RC); break;
			case '(' : strcpy(tk.type, _LB); break;
			case ')' : strcpy(tk.type, _RB); break;
			default : strcpy(tk.type, _IDENTIFIER); break;
		}	
	}
	symbol_table[tokencount - 1] = tk;
}	

void matchtoken(char *token) {
	if(strcmp(currlexem, token)) {
		flushlexem();
		scan();
	}
	else {
		error();
	}		
}

void error() {
	printf("Syntax error at line %d. Terminating...\n", linecount);
	exit(0);
}   

void scan() {
	while(lexerflag == 1) {
		currC = fgetc(input_file);
		if(currC == EOF) {
			lexerflag = 0;
		}	
		if(!isdigit(currC) && currlexem[0] != '\0' && isdigit(currlexem[0])) {
			ungetc(currC, input_file);
			break;
		}
		if(currC != '\n' && currC != '\t' && currC != ' ' && 
			currC != '\f' && currC != '\b' && currC != '\r') {
			if(currC == '+' || currC == '-' || currC == '*' || currC == '/' ||
				currC == ',' || currC == ';' || currC == '>' || currC == '<' || 
				currC == '{' || currC == '}' || currC == '(' || currC == ')') {
				if(currlexem[0] == '"') {
					currlexem[pointer++] = currC;
				}		
				else if(currlexem[0] != '\0') {
					ungetc(currC, input_file);
					lexerflag = 0;
				}
				else {
					currlexem[0] = currC;
					lexerflag = 0;
				}	
			}
			else if(currC == '=' || currC == '|' || currC == '&') {
				if(currlexem[0] == '"') {
					currlexem[pointer++] = currC;
				}
				else if(currlexem[0] == '\0') {
					currlexem[pointer++] = currC;
					currC = fgetc(input_file);
					if(currlexem[0] == currC) {
						currlexem[pointer++] = currC;
					}
					else {
						ungetc(currC, input_file);
					}
					lexerflag = 0;
				}
				else {
					ungetc(currC, input_file);
					lexerflag = 0;
				}	
			}
			else if(currC == '"') {
				currlexem[pointer++] = currC;
				if(currlexem[0] == currC && strlen(currlexem) > 1) {
					lexerflag = 0;
				}			
			}
			else if(currC == '_' || isalpha(currC) || isdigit(currC)) {
				if(currlexem[0] == '"') {
					currlexem[pointer++] = currC;
				}
				else if(isdigit(currC) && (strlen(currlexem) == 0 || isdigit(currlexem[0]))) {
					currlexem[pointer++] = currC;
					num = (num * 10) + (currC - '0');
				}
				else if(!isdigit(currC) && isdigit(currlexem[0])) {
					ungetc(currC, input_file);
					lexerflag = 0;
				}
				else {
					currlexem[pointer++] = currC;
				}			
			}			
		}
		else {
			if(currC == '\n' || currC == '\r') {
				linecount++;
				if(currlexem[0] != '\0') {
					lexerflag = 0;
				}	
			}
			else if(currC == ' ') {
				if(currlexem[0] == '"') {
					currlexem[pointer++] = currC;
				}
				else if(currlexem[0] != '\0') {
					lexerflag = 0;
				}
			}
			else if(currlexem[0] != '\0') {
				lexerflag = 0;
			}
		}				
	}
	if(currC == EOF) {
		lexerdone = 1;
		if(currlexem[0] == '\0') {
			return;
		}	
	}
	print();
	tokencount++;
	update_symbol_table();
}

